//
// Created by root on 2019/9/26.
//

#include "HotPlug.h"
#include "headerBase.h"
#include <string>

using namespace std;
#define DEBUG

static int callback(libusb_context *ctx,
                    libusb_device *device,
                    libusb_hotplug_event event,
                    void *user_data) {
    HotPlug *hotPlug = static_cast<HotPlug *>( user_data );
    libusb_device_descriptor deviceDescriptor;
    libusb_get_device_descriptor(device, &deviceDescriptor);
    printf("find usb device vid 0x%04x Pid 0x%04x   ", deviceDescriptor.idVendor, deviceDescriptor.idProduct);
    if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) {
        printf("Arrived \n");
        hotPlug->setDev(device, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED);
    } else {
        printf("Left \n");
        hotPlug->setDev(device, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT);
    }
    return 0;
}


HotPlug::HotPlug() : m_bQuit(false) {
    int ret = libusb_init(&m_context);
    CHECKUSB(ret, "init context error");
    libusb_set_debug(m_context, LIBUSB_LOG_LEVEL_INFO);
}

HotPlug::~HotPlug() {
    quit();
    m_thread.join();
    libusb_exit(m_context);
}

void HotPlug::waitPhoneIn() {
//    m_thread = thread(&HotPlug::_waitPhoneBlock, this);
    _waitPhoneBlock();
}

void HotPlug::_waitPhoneBlock() {
    int vendorId = LIBUSB_HOTPLUG_MATCH_ANY;
    int productId = LIBUSB_HOTPLUG_MATCH_ANY;
    int deviceClass = LIBUSB_HOTPLUG_MATCH_ANY;
    libusb_hotplug_flag flag = LIBUSB_HOTPLUG_ENUMERATE;
    libusb_hotplug_callback_handle handle;
    int ret = libusb_hotplug_register_callback(
            m_context, (libusb_hotplug_event)( LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED| LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT ), flag, vendorId, productId,
            deviceClass, callback, this, &handle);
    if (ret != LIBUSB_SUCCESS) {
        printf("resigter LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED failed\n");
        return;
    }

//    timeval tv = {
//            .tv_sec = 0,
//            .tv_usec = 300 * 000,
//    };

    while (!m_bQuit) {
        //设置允许处理事件的超时时间
//        libusb_handle_events_timeout(m_context, &tv);
        libusb_handle_events(m_context);
//        printf(" handle event\n");
    }
    printf(" quit libusb handle event timeout \n");
    libusb_hotplug_deregister_callback(m_context, handle);
}

void HotPlug::setDev(libusb_device *dev) {
    lock_guard<mutex> _l(m_lock);
    m_event.push(dev);
    int ret;
    libusb_device_descriptor deviceDescriptor;
    ret = libusb_get_device_descriptor(dev, &deviceDescriptor);
#ifdef  DEBUG
    CHECKUSB(ret, "open device descriptor");
    printf("usb device 0x%04x 0x%04x arrive \n", deviceDescriptor.idVendor, deviceDescriptor.idProduct);
#endif
}

libusb_device *HotPlug::getDev() {
    lock_guard<mutex> _l(m_lock);
    libusb_device *dev = m_event.front();
    m_event.pop();
    return dev;
}

bool HotPlug::arrEvent() {
    lock_guard<mutex> _l(m_lock);
    return !m_event.empty();
}
